package com.zhenyi.dati.controller;

import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import org.hashids.Hashids;
import org.joda.time.DateTime;

import com.cenjiawen.common.IndexController;
import com.cjw.model.DBMap;
import com.dati.common.model.DtPrize;
import com.dati.common.model.DtQuestion;
import com.dati.common.model.DtQuestionItem;
import com.dati.common.model.DtResult;
import com.dati.common.model.DtUser;
import com.jfinal.aop.Before;
import com.jfinal.aop.Clear;
import com.jfinal.kit.JsonKit;
import com.jfinal.kit.LogKit;
import com.jfinal.kit.PropKit;
import com.jfinal.kit.StrKit;
import com.jfinal.plugin.activerecord.Db;
import com.jfinal.plugin.activerecord.IAtom;
import com.jfinal.plugin.activerecord.SqlPara;
import com.jfinal.plugin.redis.Cache;
import com.jfinal.plugin.redis.Redis;
import com.jfinal.weixin.sdk.api.ApiConfigKit;
import com.jfinal.weixin.sdk.api.ApiResult;
import com.jfinal.weixin.sdk.api.SnsAccessToken;
import com.jfinal.weixin.sdk.api.SnsAccessTokenApi;
import com.jfinal.weixin.sdk.api.SnsApi;
import com.jfinal.weixin.sdk.api.UserApi;
import com.jfinal.weixin.sdk.kit.IpKit;
import com.utils.AuthUtils;
import com.utils.DateUtils;
import com.utils.interceptor.TestInterceptor;
import com.zhenyi.dati.core.DTAuthInterceptor;
import com.zhenyi.dati.core.DTInterceptor;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.URLUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;

@Before({ DTInterceptor.class, DTAuthInterceptor.class })
public class HomeController extends IndexController {

	/**
	 * 每天答题限制
	 */
	private final int DT_COUNT = PropKit.getInt("DT_COUNT", 3);
	private final int DT_QUESTION_COUNT = PropKit.getInt("DT_QUESTION_COUNT", 10);
	private final Cache cache = Redis.use();
	private final Hashids hashids = new Hashids("dati", 4);
	private final String APP_ID = PropKit.get("DT_APP_ID");
	private final String APP_SECRET = PropKit.get("DT_APP_SECRET");
	private final String APP_TITLE = "常见电信网络诈骗防范知识测验";

	private DtUser getUser() {
		String uid = AuthUtils.getTokenUid(this);
		return DtUser.dao.findById(uid);
	}

	@Clear
	public void debug() {
		String uid = DtUser.dao.findById(1).getId().toString();
		AuthUtils.login(uid, this);
		redirect("/dt");
	}

	/**
	 * 用户微信登录
	 */
	@Clear
	@Before(DTInterceptor.class)
	public void auth() {
		ApiConfigKit.setThreadLocalAppId(APP_ID);
		String code = getPara("code");
		if (StrKit.isBlank(code)) {
			LogKit.info(IpKit.getRealIpV2(getRequest()));
			renderError(404);
			return;
		}
		SnsAccessToken snsAccessToken = SnsAccessTokenApi.getSnsAccessToken(APP_ID, APP_SECRET, code);
		if (!snsAccessToken.isAvailable()) {
			LogKit.error("snsAccessToken error");
			renderError(404);
			return;

		}
		String openId = snsAccessToken.getOpenid();
		String accessToken = snsAccessToken.getAccessToken();
		ApiResult snsApi = SnsApi.getUserInfo(accessToken, openId);
		if (!snsApi.isSucceed()) {
			LogKit.error("snsApi error");
			renderError(404);
			return;
		}
		ApiResult userApi = UserApi.getUserInfo(openId);
		if (!userApi.isSucceed()) {
			renderError(404);
			return;
		}
		if (!userApi.getInt("subscribe").equals(1)) {
			renderContent(APP_TITLE, "请关注公众号", "", "");
			return;
		}
		// System.out.println(snsApi.getJson());
		// System.out.println(openId);
		// System.out.println(userApi.getJson());
		/**
		 * 如果用户不存在,创建新用户
		 */
		DtUser user = DtUser.dao.searchFirst("openId", openId);
		if (user == null) {
			user = new DtUser();
			user.setOpenId(openId);
			user.save();
		}
		user.setSex(snsApi.getInt("sex"));
		user.setNickname(snsApi.getStr("nickname"));
		user.setLogo(snsApi.getStr("headimgurl"));
		user.setCity(snsApi.getStr("city"));
		user.setProvince(snsApi.getStr("province"));
		user.setCountry(snsApi.getStr("country"));
		user.setLastLoginTime(new Date());
		user.update();
		AuthUtils.login(String.valueOf(user.getId()), this);
		String state = getPara("state");
		if (StrKit.isBlank(state)) {
			redirect("/");
		} else {
			redirect(URLUtil.decode(state));
		}
	}

	/**
	 * 获得问题列表
	 */
	@Override
	public void index() {
		if (isDrawed()) {
			renderContent(APP_TITLE, "已中奖 ", "恭喜balabal", "");
			information();
			return;
		}
		if (!isHavePrize()) {
			renderContent(APP_TITLE, "答题活动已结束", "谢谢参与", "");
			return;
		}
		if (remainingChance() == 0) {
			renderContent(APP_TITLE, "今天已答题超过" + DT_COUNT + "次", "请明天再来", "");
			return;
			// setAttr("noChance", 1);
		}
		List<DtQuestion> questions = getRandomQuestions();
		setAttr("chance", remainingChance());
		setAttr("questions", questions);
		render("/dt/index.html");
	}

	/**
	 * 缓存答题机会次数
	 * 
	 * @return
	 */
	private String getCacheKey() {
		DtUser user = getUser();
		String key = "dt-" + user.getId();
		return key;
	}

	/**
	 * 是否还有奖品
	 * 
	 * @return
	 */
	private boolean isHavePrize() {
		SqlPara sqlPara = Db.use("dati").getSqlPara("DTFindPrizes");
		List<DtPrize> prizes = DtPrize.dao.find(sqlPara);
		if (prizes.size() == 0) {
			return false;
		}
		return true;
	}

	/**
	 * 今天剩余答题机会
	 * 
	 * @return
	 */
	private int remainingChance() {
		String key = getCacheKey();
		Integer attemp = cache.get(key);
		if (attemp == null) {
			return DT_COUNT;
		} else if (attemp.intValue() < DT_COUNT) {
			return DT_COUNT - attemp.intValue();
		}
		return 0;
	}

	/**
	 * 是否已中奖
	 * 
	 * @return
	 */
	private boolean isDrawed() {
		DtUser user = getUser();
		Long userId = user.getId();
		DtResult result = DtResult.dao.searchFirst("userId", userId);
		return result != null;
	}

	@Before(TestInterceptor.class)
	public void logout() {
		AuthUtils.logout(this);
		// renderSuccess();
		redirect("/dt");
	}

	/**
	 * 随机问题
	 * 
	 * @return
	 */
	private List<DtQuestion> getRandomQuestions() {
		List<DtQuestion> items = DtQuestion.dao.findAll();
		ArrayList<DtQuestion> questions = new ArrayList<>();
		for (int index = 0; index < DT_QUESTION_COUNT; index++) {
			int size = items.size();
			int ran = RandomUtil.randomInt(0, size);
			DtQuestion question = items.remove(ran);
			questions.add(question);
		}
		for (DtQuestion dtQuestion : questions) {
			SqlPara sqlPara = Db.use("dati").getSqlPara("DTFindQuestionItems", dtQuestion.getId());
			List<DtQuestionItem> questionItems = DtQuestionItem.dao.find(sqlPara);
			dtQuestion.put("items", questionItems);
		}
		return questions;
	}

	/**
	 * 检查答案是否全对
	 * 
	 * @return
	 */
	private boolean checkAnswers() {
		String answer = getPara("answer");
		if (StrKit.isBlank(answer)) {
			LogKit.info("answer 空");
			return false;
		}
		DBMap map = new DBMap();
		JSONArray jsonArray = new JSONArray(answer);
		int arraySize = jsonArray.size();
		if (arraySize < DT_QUESTION_COUNT) {
			LogKit.info("没答够题" + arraySize + ":" + DT_QUESTION_COUNT);
			return false;
		}
		for (Object object : jsonArray) {
			JSONObject jsonObject = new JSONObject(object);
			long questionId = jsonObject.getLong("questionId");
			map.put(String.valueOf(questionId), "check");
			String items = jsonObject.getStr("items");
			if (StrKit.isBlank(items)) {
				LogKit.info(questionId + ":选项 空");
				return false;
			}
			int itemLen = items.split(";").length;
			SqlPara sqlPara = Db.use("dati").getSqlPara("DTFindCorrectItems", questionId);
			List<DtQuestionItem> correntItems = DtQuestionItem.dao.find(sqlPara);
			if (correntItems.size() != itemLen) {
				LogKit.info(questionId + ":选项长度和答案长度不同");
				return false;
			}
			for (DtQuestionItem dtQuestionItem : correntItems) {
				Long correctId = dtQuestionItem.getId();
				if (!items.contains(String.valueOf(correctId))) {
					LogKit.info(questionId + ":选项 包含错误答案");
					return false;
				}
			}
		}
		int mapSize = map.size();
		if (mapSize < DT_QUESTION_COUNT) {
			LogKit.info("没提交够:" + mapSize);
			return false;
		}
		return true;
	}

	@Clear
	public void test() {
		SqlPara sqlPara = Db.use("dati").getSqlPara("DTFindPrizes");
		List<DtPrize> prizes = DtPrize.dao.find(sqlPara);
		for (DtPrize dtPrize : prizes) {
			System.out.println(JsonKit.toJson(dtPrize));
		}
		int prizeSize = prizes.size();
		if (prizeSize == 0) {
			renderFailure();
			return;
		}
		int index = prizeSize == 1 ? 0 : RandomUtil.randomInt(0, prizeSize);
		System.out.println("idx:" + index);
		DtPrize prize = prizes.get(index);
		renderResult(prize);
	}

	@Override
	public void submit() {
		int remain = remainingChance();
		if (remain == 0) {
			// renderMsg("没有答题机会了");
			renderResult("今天剩余答题次数为" + remain, "ok", 201);
			return;
		}
		if (isDrawed()) {
			renderMsg("已中奖");
			return;
		}
		String key = getCacheKey();
		Integer attemp = cache.get(key);
		String today = DateUtil.today() + " 00:00:00";
		Date date = DateUtils.dateFromString(today, DateUtils.YYYYMMDD_HHMMSS);
		date = new DateTime(date).plusDays(1).toDate();
		long seconds = date.getTime() - new Date().getTime();
		int time = Integer.parseInt(String.valueOf(seconds)) / 1000;
		if (attemp == null) {
			cache.setex(key, time, 1);
		} else {
			cache.setex(key, time, attemp + 1);
		}

		boolean isAllCorrect = checkAnswers();
		if (!isAllCorrect) {
			renderMsg("没全对");
			return;
		}

		boolean flag = Db.tx(new IAtom() {

			@Override
			public boolean run() throws SQLException {
				SqlPara sqlPara = Db.use("dati").getSqlPara("DTFindPrizes");
				List<DtPrize> prizes = DtPrize.dao.find(sqlPara);
				int prizeSize = prizes.size();
				if (prizeSize == 0) {
					return false;
				}
				int index = prizeSize == 1 ? 0 : RandomUtil.randomInt(0, prizeSize);
				DtPrize prize = prizes.get(index);
				prize.setStock(prize.getStock() - 1);
				prize.update();
				DtResult result = new DtResult();
				DtUser user = getUser();
				Long userId = user.getId();
				result.setUserId(userId);
				result.setContent(prize.getContent());
				result.setPrizeId(prize.getId());
				result.save();
				result.setCode(hashids.encode(result.getId()));
				result.update();
				return true;
			}
		});
		if (flag) {
			renderSuccess();
			return;
		} else {
			renderMsg("奖答题活动已结束,谢谢参与");
			return;
		}
	}

	private void renderContent(String header, String title, String content, String image) {
		setAttr("header", header);
		setAttr("title", title);
		setAttr("content", content);
		if (StrKit.notBlank(image)) {
			setAttr("image", image);
		}
		render("/dt/content.html");
	}

	private void renderContent(String title, String content, String image) {
		renderContent(APP_TITLE, title, content, image);
	}

	/**
	 * 抽奖
	 */
	public void draw() {
		DtUser user = getUser();
		Long userId = user.getId();
		DtResult result = DtResult.dao.searchFirst("userId", userId);
		if (result == null) {
			renderContent(APP_TITLE, "很遗憾,没有中奖", "", "");
			return;
		}
		DtPrize prize = DtPrize.dao.findById(result.getPrizeId());
		setAttr("prize", prize);
		render("/dt/luckyDraw.html");
	}

	/**
	 * 填写中奖信息
	 */
	public void form() {
		renderSuccess();
	}

	public void submitInfo() {
		String name = getPara("name");
		String mobile = getPara("mobile");
		String address = getPara("address");
		String weixin = getPara("weixin");
		DtUser user = getUser();
		Long userId = user.getId();
		DtResult result = DtResult.dao.searchFirst("userId", userId);
		if (result == null) {
			renderFailure();
			return;
		}
		result.setMobile(mobile);
		result.setName(name);
		result.setAddress(address);
		result.setWeixin(weixin);
		result.update();
		renderSuccess(result.getCode());
	}

	/**
	 * 中奖信息
	 */
	public void information() {
		DtUser user = getUser();
		Long userId = user.getId();
		DtResult result = DtResult.dao.searchFirst("userId", userId);
		if (result == null) {
			renderContent("很遗憾,没有中奖", "", "");
			return;
		}
		String code = result.getCode();
		if (code == null) {
			renderContent(APP_TITLE, "很遗憾,没有中奖.", "", "");
			return;
		}
		setAttr("info", result);
		render("/dt/info.html");
	}

	/**
	 * 结果
	 */
	public void result() {
		renderContent("成功", "", "");
	}

}
